package calc;

import java.awt.event.ActionEvent;
import java.math.BigDecimal;
import java.math.MathContext;

import javax.swing.AbstractAction;
import javax.swing.JFrame;

import calc.buttonPanel.ControlPanel;
import calc.buttonPanel.DispPanel;
import calc.buttonPanel.NumPanel;
import calc.buttonPanel.OperatorPanel;

public class CalFrame extends JFrame {
	private NumPanel numPanel;
	private DispPanel dispPanel;
	private ControlPanel conPanel;
	private OperatorPanel operPanel;

	private String num1;
	private String num2;
	private StringBuilder current = new StringBuilder("0");
	private String history = new String();
	private String operator;

	private int state;

	public CalFrame() {
		setTitle("Michael's Calculator");
		setSize(300, 400);
		setResizable(false);
		setLayout(null);

		dispPanel = new DispPanel();
		dispPanel.setBounds(10, 10, 280, 75);
		add(dispPanel, null);

		// 添加控制按钮面板，并给其中按钮添加监听器
		conPanel = new ControlPanel();
		conPanel.setBounds(10, 90, 160, 50);
		add(conPanel);

		conPanel.getResetButton().addActionListener(new ResetAction());
		conPanel.getClearButton().addActionListener(new ClearAction());
		conPanel.getBackButton().addActionListener(new BackAction());

		// 添加数字按钮面板，并给其中按钮添加监听器
		numPanel = new NumPanel();
		numPanel.setBounds(10, 145, 160, 215);
		add(numPanel, null);

		for (int i = 0; i < 10; i++) {
			numPanel.getNumButton()[i]
					.addActionListener(new CalFrame.NumAction((char) (i + 48)));
		}
		numPanel.getNumButton()[10].addActionListener(new NumAction('.'));

		// 添加操作符按钮面板，并给其中按钮添加监听器
		operPanel = new OperatorPanel();
		operPanel.setBounds(175, 90, 105, 270);
		add(operPanel);

		operPanel.getJiaButton().addActionListener(new DoubleOperAction("+"));
		operPanel.getJianButton().addActionListener(new DoubleOperAction("-"));
		operPanel.getChengButton().addActionListener(new DoubleOperAction("×"));
		operPanel.getChuButton().addActionListener(new DoubleOperAction("÷"));

		operPanel.getDengButton().addActionListener(new SingleOperAction("="));
		operPanel.getDaoButton().addActionListener(new SingleOperAction("1/x"));
		operPanel.getFanButton().addActionListener(new SingleOperAction("±"));
		operPanel.getGenButton().addActionListener(new SingleOperAction("√"));
		operPanel.getBaiButton().addActionListener(new SingleOperAction("%"));
	}

	class NumAction extends AbstractAction {

		private char c;

		public NumAction(char c) {
			this.c = c;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			if (state == 2) {
				num2 = null;
			}

			if (current.toString().equals("0") && c != '.') {
				current = new StringBuilder(c + "");
			} else {
				current.append(c);
			}

			dispPanel.getCurrentDisp().setText(current.toString());
			state = 0;
		}

	}

	class ResetAction extends AbstractAction {

		@Override
		public void actionPerformed(ActionEvent e) {
			history = new String();
			current = new StringBuilder("0");
			num1 = null;
			num2 = null;
			operator = null;

			dispPanel.getHistoryDisp().setText("");
			dispPanel.getCurrentDisp().setText("0");
			dispPanel.repaint();

		}

	}

	class ClearAction extends AbstractAction {

		@Override
		public void actionPerformed(ActionEvent e) {
			current = new StringBuilder("0");
			dispPanel.getCurrentDisp().setText("0");
			dispPanel.repaint();
		}

	}

	class BackAction extends AbstractAction {

		@Override
		public void actionPerformed(ActionEvent e) {
			if (current.length() > 1) {
				current.deleteCharAt(current.length() - 1);
			} else if (current.length() == 1) {
				if (current.charAt(0) == '0') {

				} else {
					current.setCharAt(0, '0');
				}
			}
			dispPanel.getCurrentDisp().setText(current.toString());
			dispPanel.repaint();
		}

	}

	class DoubleOperAction extends AbstractAction {

		private String op;

		public DoubleOperAction(String op) {
			super(op);
			this.op = op;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			if (num1 == null) {
				num1 = current.toString();
				operator = op;
				history = num1 + " " + op;
			} else {
				if (state == 1 && num2 != null) {

					calculate(num1, num2, operator);

					if ((op.equals("×") || op.equals("÷"))
							&& history.indexOf(" ") != -1) {
						history = "(" + history + " " + num2 + ") " + op;
					} else {
						history = history + " " + num2 + " " + op;
					}

				} else if (state == 2) {
					if(!operator.equals("=")) {
						history = "("+history+") "+op;
					} else {		
						history = history + " " + op;
					}

				} else {

					num2 = current.toString();
					calculate(num1, num2, operator);

					if ((op.equals("×") || op.equals("÷"))
							&& history.indexOf(" ") != -1) {
						history = "(" + history + " " + num2 + ") " + op;
					} else {
						history = history + " " + num2 + " " + op;
					}
				}

			}

			current = new StringBuilder("0");
			operator = op;
			dispPanel.getCurrentDisp().setText(num1);
			dispPanel.getHistoryDisp().setText(history);

			state = 1;

		}

	}

	class SingleOperAction extends AbstractAction {

		private String op;

		public SingleOperAction(String op) {
			super(op);
			this.op = op;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			if (num1 == null) {
				num1 = current.toString();
				if (op.endsWith("=")) {
					history = num1 + "";
				} else if (op.equals("%")) {
					history = num1 + "%";
				} else if (op.equals("1/x")) {
					history = "1 / " + num1;
				} else if (op.equals("√")) {
					history = "sqrt(" + num1 + ")";
				} else if (op.equals("±")) {
					history = "- " + num1;
				}

			} else {
				if (num2 == null) {
				
					num2 = current.toString();
				}
				
				if(calculate(num1,num2,operator)) {
					history = history +" "+num2;
				}
				

				if (op.endsWith("=")) {
					history = history + "";
				} else if (op.equals("%")) {
					history = "(" + history + ")%";
				} else if (op.equals("1/x")) {
					history = "1 / (" + history + ")";
				} else if (op.equals("√")) {
					history = "sqrt(" + history + ")";
				} else if (op.equals("±")) {
					history = "- (" + history + ")";
				}

			}
			calculate(num1, op);
			current = new StringBuilder("0");
			operator = op;
			dispPanel.getCurrentDisp().setText(num1);
			dispPanel.getHistoryDisp().setText(history);

			state = 2;

		}

	}

	private boolean calculate(String num1, String num2, String op) {
		BigDecimal n1 = new BigDecimal(num1);
		BigDecimal n2 = new BigDecimal(num2);
		MathContext mc = MathContext.DECIMAL32;

		if (op.equals("+")) {
			n1 = n1.add(n2, mc);
			this.num1 = n1.toString();
			return true;
		}

		if (op.equals("-")) {
			n1 = n1.subtract(n2, mc);
			this.num1 = n1.toString();
			return true;
		}

		if (op.equals("×")) {
			n1 = n1.multiply(n2, mc);
			this.num1 = n1.toString();
			return true;
		}

		if (op.equals("÷")) {
			n1 = n1.divide(n2, mc);
			this.num1 = n1.toString();
			return true;
		}
		
		return false;
	}

	private boolean calculate(String num1, String op) {
		BigDecimal n1 = new BigDecimal(num1);
		MathContext mc = MathContext.DECIMAL32;

		if (op.equals("%")) {
			n1 = n1.movePointRight(2);
			this.num1 = n1.toString();
			return true;
		}

		if (op.equals("=")) {
			return true;
		}

		if (op.equals("1/x")) {
			n1 = BigDecimal.ONE.divide(n1, mc);
			this.num1 = n1.toString();
			return true;
		}

		if (op.equals("√")) {
			double d = Double.valueOf(num1);
			n1 = new BigDecimal(Math.sqrt(d), mc);
			this.num1 = n1.toString();
			return true;
		}

		if (op.equals("±")) {
			if (num1.charAt(0) == '-') {
				num1 = num1.substring(1);
			} else {
				num1 = "-" + num1;
			}
			return true;
		}
		
		return false;

	}

}
